﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;

namespace XmlStudio.Classes {
    /// <summary>
    /// Represents read-only dictionary.
    /// </summary>
    /// <typeparam name="TKey">Key type.</typeparam>
    /// <typeparam name="TValue">Value type.</typeparam>
    public class ReadOnlyDictionary<TKey, TValue> : IDictionary<TKey, TValue> {
        private IDictionary<TKey, TValue> _dictionary;

        /// <summary>
        /// Initializes a new instance of the <see cref="ReadOnlyDictionary{TKey, TValue}"/> class.
        /// </summary>
        /// <param name="source">Source.</param>
        public ReadOnlyDictionary(IDictionary<TKey, TValue> source) {
            _dictionary = source;
        }

        /// <summary>
        /// Gets enumerator.
        /// </summary>
        /// <returns>Enumerator.</returns>
        public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator() {
            foreach(KeyValuePair<TKey, TValue> item in _dictionary) {
                yield return item;
            }
        }

        IEnumerator IEnumerable.GetEnumerator() {
            return GetEnumerator();
        }

        /// <summary>
        /// Gets value whether the dictionary contains the key.
        /// </summary>
        /// <param name="key">Key.</param>
        /// <returns>True if key is present, false otherwise.</returns>
        public bool ContainsKey(TKey key) {
            return _dictionary.ContainsKey(key);
        }

        /// <summary>
        /// Tries to get the value according to the key.
        /// </summary>
        /// <param name="key">Key.</param>
        /// <param name="value">Value (out parameter).</param>
        /// <returns>True if succeeded, false otherwise.</returns>
        public bool TryGetValue(TKey key, out TValue value) {
            return _dictionary.TryGetValue(key, out value);
        }

        /// <summary>
        /// Gets value whether the dictionary contains the key value pair.
        /// </summary>
        /// <param name="item">Item to find.</param>
        /// <returns>True if found, false otherwise.</returns>
        public bool Contains(KeyValuePair<TKey, TValue> item) {
            return _dictionary.Contains(item);
        }

        /// <summary>
        /// Copies the key value pairs to an array.
        /// </summary>
        /// <param name="array">Where to copy.</param>
        /// <param name="arrayIndex">Index where to copy.</param>
        public void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex) {
            _dictionary.CopyTo(array, arrayIndex);
        }

        /// <summary>
        /// Gets the value according to the key.
        /// </summary>
        /// <param name="key">Key.</param>
        /// <returns>Value.</returns>
        public TValue this[TKey key] {
            get {
                return _dictionary[key];
            }
        }

        TValue IDictionary<TKey, TValue>.this[TKey key] {
            get {
                return this[key];
            }
            set {
                throw new NotSupportedException();
            }
        }

        /// <summary>
        /// Gets the collection of keys.
        /// </summary>
        public ICollection<TKey> Keys {
            get {
                ReadOnlyCollection<TKey> keys =
                    new ReadOnlyCollection<TKey>(new List<TKey>(_dictionary.Keys));
                return (ICollection<TKey>)keys;
            }
        }

        /// <summary>
        /// Gets the collection of values.
        /// </summary>
        public ICollection<TValue> Values {
            get {
                ReadOnlyCollection<TValue> values =
                    new ReadOnlyCollection<TValue>(new List<TValue>(_dictionary.Values));
                return (ICollection<TValue>)values;
            }
        }

        /// <summary>
        /// Gets the number of items.
        /// </summary>
        public int Count {
            get {
                return _dictionary.Count;
            }
        }

        /// <summary>
        /// Gets the value indicating whether the dictionary is read-only.
        /// </summary>
        public bool IsReadOnly {
            get { return true; }
        }

        void IDictionary<TKey, TValue>.Add(TKey key, TValue value) {
            throw new NotSupportedException();
        }

        bool IDictionary<TKey, TValue>.Remove(TKey key) {
            throw new NotSupportedException();
        }

        void ICollection<KeyValuePair<TKey, TValue>>.Add(KeyValuePair<TKey, TValue> item) {
            throw new NotSupportedException();
        }

        bool ICollection<KeyValuePair<TKey, TValue>>.Remove(KeyValuePair<TKey, TValue> item) {
            throw new NotSupportedException();
        }

        void ICollection<KeyValuePair<TKey, TValue>>.Clear() {
            throw new NotSupportedException();
        }
    }
}
